Skip to content

feat(phase-3): RabbitMQ plan sync, CI, Docker hardening, search resil…#1

Merged
Dalamov merged 1 commit intomainfrom
feature/phase-3-ci-rabbitmq-resilience
Mar 22, 2026
Merged

feat(phase-3): RabbitMQ plan sync, CI, Docker hardening, search resil…#1
Dalamov merged 1 commit intomainfrom
feature/phase-3-ci-rabbitmq-resilience

Conversation

@Dalamov
Copy link
Copy Markdown
Owner

@Dalamov Dalamov commented Mar 22, 2026

…ience

  • Add AMQP publisher/consumer, DLQ topology, worker service, POST /jobs/plan-sync
  • GitHub Actions: PHPUnit unit + Postgres integration tests; MIT LICENSE
  • Dev image: PHP_BASE_IMAGE (ECR mirror), .dockerignore, Make ready/pull-base
  • Search cache: epoch invalidation, stampede lock; provider client timeouts/retry/circuit
  • PlanListParser: suppress libxml noise on invalid XML; php-amqplib dependency

Made-with: Cursor


Note

Medium Risk
Introduces a new async plan-sync execution path via RabbitMQ and a new public endpoint (POST /jobs/plan-sync), plus changes search caching semantics; these affect operational behavior and failure modes across Redis/RabbitMQ.

Overview
Adds asynchronous plan sync via RabbitMQ. Introduces PlanSyncJobPublisherPort with an AMQP implementation that declares exchange/queue/DLQ topology, plus a long-running consumer and new POST /jobs/plan-sync endpoint (and CLI scripts/enqueue-plan-sync.php) to enqueue durable sync jobs.

Improves /search caching robustness. Switches cache invalidation from wildcard deletes to epoch-based keys and adds single-flight locking + wait loop to reduce cache stampedes; TTL is now configurable via CACHE_SEARCH_TTL.

Hardens ops/dev tooling. Adds a worker-plan-sync Compose service, multi-stage Dockerfile with configurable PHP_BASE_IMAGE mirror, a .dockerignore, expanded Make targets (ready, pull-base, readiness wait), and a GitHub Actions workflow running unit + Postgres integration tests; updates .env.example, README, and adds MIT LICENSE.

Written by Cursor Bugbot for commit fd13210. This will update automatically on new commits. Configure here.

…ience

- Add AMQP publisher/consumer, DLQ topology, worker service, POST /jobs/plan-sync
- GitHub Actions: PHPUnit unit + Postgres integration tests; MIT LICENSE
- Dev image: PHP_BASE_IMAGE (ECR mirror), .dockerignore, Make ready/pull-base
- Search cache: epoch invalidation, stampede lock; provider client timeouts/retry/circuit
- PlanListParser: suppress libxml noise on invalid XML; php-amqplib dependency

Made-with: Cursor
@Dalamov Dalamov merged commit 402de18 into main Mar 22, 2026
3 checks passed
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

}
}

return $this->loadFromDatabaseAndCache($cacheKey, $startsAt, $endsAt);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stampede loop adds 1.5s latency when Redis is down

Medium Severity

When Redis is unavailable, setIfNotExists returns false (the executeWithFallback default), which is indistinguishable from "another request holds the lock." This causes every search request to fall through to the polling loop, sleeping 30 × 50ms = 1.5 seconds before finally querying PostgreSQL. The README states "if Redis is down, search still reads PostgreSQL," but the stampede protection silently degrades every request with a significant blocking delay instead of falling through immediately to the database.

Additional Locations (1)
Fix in Cursor Fix in Web

- PROVIDER_URL=${PROVIDER_URL}
- PROVIDER_FIXTURE_PATH=${PROVIDER_FIXTURE_PATH}
- PROVIDER_URL=${PROVIDER_URL:-}
- PROVIDER_FIXTURE_PATH=${PROVIDER_FIXTURE_PATH:-tests/Fixtures/provider_responses/response_1.xml}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing RABBITMQ_VHOST in app service environment

Medium Severity

The app service environment is missing RABBITMQ_VHOST, while worker-plan-sync includes it. When a non-default vhost is configured in .env, AmqpPlanSyncJobPublisher::fromEnvironment() running inside the app container will always fall back to vhost /, while the consumer in the worker container will use the configured vhost. Published messages go to the wrong vhost and are never consumed.

Additional Locations (1)
Fix in Cursor Fix in Web

docs
tests
.env
.env.*
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dockerignore missing vendor breaks prod image build

Medium Severity

The new .dockerignore omits vendor/. The new prod Dockerfile target runs composer install --no-dev then COPY . .. On any machine where composer install was run on the host (e.g. via make install), COPY . . overwrites the container's --no-dev vendor directory with the host's full vendor tree including dev dependencies like PHPUnit. The documented prod build command produces an image with dev dependencies baked in.

Additional Locations (1)
Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant